package com.xusiyan08.service;

import com.xusiyan08.entity.Item;
import com.xusiyan08.entity.User;
import com.xusiyan08.repository.ItemRepository;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.List;

@Service
public class ItemService {
    private static final Logger logger = LoggerFactory.getLogger(ItemService.class);

    @Autowired
    private ItemRepository itemRepository;

    @Autowired
    private UserService userService;

    @Value("${file.upload-dir:uploads}")
    private String uploadDir;

    @PostConstruct
    public void init() {
        try {
            Path uploadPath = Paths.get(uploadDir);
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
                logger.info("Created upload directory: {}", uploadPath.toAbsolutePath());
            }
        } catch (IOException e) {
            throw new RuntimeException("Could not create upload directory!", e);
        }
    }

    @Transactional
    public Item createItem(Item itemDetails, Long sellerId, String studentId, MultipartFile[] imageFiles, Integer primaryImageIndex) {
        logger.info("Creating item: {}, seller: {}, studentId: {}, images: {}, primaryIndex: {}",
                itemDetails.getTitle(), sellerId, studentId,
                imageFiles != null ? imageFiles.length : 0, primaryImageIndex);

        itemDetails.setCreatedAt(LocalDateTime.now());
        itemDetails.setUpdatedAt(LocalDateTime.now());
        if (itemDetails.getStatus() == null) {
            itemDetails.setStatus(Item.Status.审核中);
        }
        itemDetails.setSellerId(sellerId);
        itemDetails.setStudentId(studentId);
        itemDetails.setPrimaryImageIndex(primaryImageIndex);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        if (imageFiles != null && imageFiles.length > 0) {
            for (int i = 0; i < imageFiles.length; i++) {
                MultipartFile imageFile = imageFiles[i];
                if (imageFile == null || imageFile.isEmpty()) {
                    logger.warn("Empty image file at index: {}", i);
                    continue;
                }

                try {
                    byte[] bytes = imageFile.getBytes();
                    outputStream.write(bytes);
                    logger.info("Processed image [{}]: Name=\'{}\', Size=\'{} bytes\'", i, imageFile.getOriginalFilename(), bytes.length);
                } catch (IOException e) {
                    logger.error("Could not read bytes from file " + imageFile.getOriginalFilename(), e);
                }
            }
        }

        if (outputStream.size() > 0) {
            itemDetails.setImages(outputStream.toByteArray());
        } else {
            itemDetails.setImages(null);
        }

        Item savedItem = itemRepository.save(itemDetails);
        logger.info("Item saved with ID: {}", savedItem.getItemId());
        return savedItem;
    }

    @Transactional
    public Item updateItem(Long itemId, Item itemDetails, MultipartFile[] imageFiles, Long currentUserId) {
        logger.info("Updating item with ID: {} by user {}", itemId, currentUserId);
        Item item = itemRepository.findById(itemId)
                .orElseThrow(() -> new RuntimeException("Item not found with id: " + itemId));

        // *** Permission Check: Only the seller can update the item ***
        if (!item.getSellerId().equals(currentUserId)) {
            logger.warn("User {} attempted to update item {} but is not the seller {}", currentUserId, itemId, item.getSellerId());
            // You might want to throw a more specific exception like org.springframework.security.access.AccessDeniedException
            throw new RuntimeException("You do not have permission to update this item.");
        }
        // ***********************************************************

        // Update fields if provided in itemDetails
        if (itemDetails.getTitle() != null) item.setTitle(itemDetails.getTitle());
        if (itemDetails.getDescription() != null) item.setDescription(itemDetails.getDescription());
        if (itemDetails.getPrice() != null) item.setPrice(itemDetails.getPrice());
        // Category update is not included in the current frontend form, but adding it here for completeness
        if (itemDetails.getCategory() != null) item.setCategory(itemDetails.getCategory());
        if (itemDetails.getStatus() != null) item.setStatus(itemDetails.getStatus()); // Update status

        // Process and update images only if new images are provided and not empty
        if (imageFiles != null && imageFiles.length > 0 && imageFiles[0] != null && !imageFiles[0].isEmpty()) {
            logger.info("Processing {} new image(s) for item with ID: {}", imageFiles.length, itemId);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            for (int i = 0; i < imageFiles.length; i++) {
                MultipartFile imageFile = imageFiles[i];
                if (imageFile == null || imageFile.isEmpty()) {
                    logger.warn("Empty image file at index: {}", i);
                    continue;
                }
                try {
                    outputStream.write(imageFile.getBytes());
                } catch (IOException e) {
                    logger.error("Could not read bytes from file " + imageFile.getOriginalFilename(), e);
                    // Depending on requirements, you might want to throw an exception or handle this error differently
                }
            }
            if (outputStream.size() > 0) {
                item.setImages(outputStream.toByteArray());
            } else {
                item.setImages(null);
            }
        }
        // If imageFiles is null or empty or contains only empty files, keep the existing images.

        item.setUpdatedAt(LocalDateTime.now());
        Item updatedItem = itemRepository.save(item);
        logger.info("Item updated with ID: {}", updatedItem.getItemId());
        return updatedItem;
    }

    @Transactional
    public void deleteItem(Long itemId) {
        logger.info("Deleting item with ID: {}", itemId);
        itemRepository.deleteById(itemId);
        logger.info("Item with ID: {} deleted.", itemId);
    }

    public Item getItemById(Long itemId) {
        logger.info("Fetching item with ID: {}", itemId);
        Item item = itemRepository.findWithImagesById(itemId).orElse(null);
        if (item != null) {
            logger.info("Found item with ID: {}", itemId);
            logger.info("Item {} sellerId: {}", itemId, item.getSellerId());

            // Fetch seller details and set nickname
            User seller = userService.getUserById(item.getSellerId());
            if (seller != null) {
                item.setSellerNickname(seller.getNickname());
                // You might also want to set the seller's studentId if needed for chat
                // item.setStudentId(seller.getStudentId()); // If StudentId is needed on the item object
            }

            // Convert image BLOB to Base64 for frontend display
            byte[] imagesBytes = item.getImages();
            if (imagesBytes != null && imagesBytes.length > 0) {
                String base64Image = java.util.Base64.getEncoder().encodeToString(imagesBytes);
                item.setBase64Image("data:image/jpeg;base64," + base64Image); // Assuming JPEG
            }
        } else {
            logger.warn("Item with ID: {} not found.", itemId);
        }
        return item;
    }

    public List<Item> getAllItems() {
        logger.info("Fetching all available items (出售中)");
        List<Item> items = itemRepository.findAllAvailableItems(Item.Status.出售中);
        logger.info("Found {} available items.", items.size());
        // Convert image BLOB to Base64 for each item in the list
        processItemListForImageDisplay(items);
        return items;
    }

    public List<Item> getItemsBySeller(Long sellerId) {
        logger.info("Fetching items for sellerId: {}", sellerId);
        List<Item> items = itemRepository.findBySellerId(sellerId);
        logger.info("Found {} {} items for sellerId: {}", items.size(), (items.size() == 1 ? "item" : "items"), sellerId);
        // Convert image BLOB to Base64 for each item in the list
        processItemListForImageDisplay(items);
        return items;
    }

    public List<Item> searchItems(String keyword) {
        logger.info("Searching for items with keyword: {}", keyword);
        List<Item> items = itemRepository.searchByKeyword(keyword);
        logger.info("Found {} items for keyword: {}", items.size(), keyword);
        // Convert image BLOB to Base64 for each item in the list
        processItemListForImageDisplay(items);
        return items;
    }

    public List<Item> getItemsByStatus(Item.Status status) {
        logger.info("Fetching items with status: {}", status);
        List<Item> items = itemRepository.findByStatus(status);
        logger.info("Found {} items with status: {}", items.size(), status);
        // Convert image BLOB to Base64 for each item in the list
        processItemListForImageDisplay(items);
        return items;
    }

    @Transactional
    public Item updateItemStatus(Long itemId, Item.Status status) {
        logger.info("Updating status for item with ID: {} to {}", itemId, status);
        Item item = itemRepository.findById(itemId)
                .orElseThrow(() -> new RuntimeException("Item not found with id: " + itemId));

        item.setStatus(status);
        item.setUpdatedAt(LocalDateTime.now());
        Item updatedItem = itemRepository.save(item);
        logger.info("Item status updated for ID: {}", updatedItem.getItemId());
        return updatedItem;
    }

    public List<Item> getAllItemsWithDetails() {
        logger.info("Fetching all items with details.");
        List<Item> items = itemRepository.findAll(); // Assuming findAllWithImages is no longer needed/correct
        logger.info("Found {} items with details.", items.size());
        // Convert image BLOB to Base64 for each item in the list
        processItemListForImageDisplay(items);
        return items;
    }

    public void processItemListForImageDisplay(List<Item> items) {
        if (items == null) {
            return;
        }
        for (Item item : items) {
            byte[] imagesBytes = item.getImages();
            if (imagesBytes != null && imagesBytes.length > 0) {
                String base64Image = java.util.Base64.getEncoder().encodeToString(imagesBytes);
                item.setBase64Image("data:image/jpeg;base64," + base64Image); // Assuming JPEG
            }
        }
    }
}